package com.jeremy.comutils.utils;

import com.jeremy.comutils.domain.ComParamConfig;
import com.jeremy.comutils.exception.CustomComException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TcpAndUdpTest {
    //创建LOG对象
    private static final Logger logger = LogManager.getLogger();

    //声明测试串口
    public static String jeremyComPort;

    //统计出错次数
    private static int errorCount = 0;

    //统计出错发生处集合
    private static HashSet<Integer> errList = new LinkedHashSet<>();

    //控制是否打印匹配失败次数的log
    private static boolean flag = false;

    //初始化串口操作对象
    private static SerialPortUtils serialPort;

    //统计发起连接次数
    private static int connectTimes = 0;

    //统计连接成功次数
    private static int connectSuccessTimes = 0;

    //统计连接失败次数
    private static int timeoutTimes = 0;

    //统计连接中断次数
    private static int connectionClosedTimes = 0;

    //统计收不到服务器回复的次数
    private static int canNotGetServerReplayTimes = 0;

    //初始化测试服务器
    private static String serverType;
    private static String serverAddress;
    private static String serverPort;

    //十进制转十六进制方法
    private static String intToHex(int n) {
        StringBuilder sb = new StringBuilder(8);
        String a;
        char[] b = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        while (n != 0) {
            sb.append(b[n % 16]);
            n = n / 16;
        }
        a = sb.reverse().toString();
        return a;
    }

    private static void init() throws CustomComException, InterruptedException {
        serialPort.sendComm("AT+CIPSHUT\r\n");
        Thread.sleep(3000L);
        serialPort.sendComm("AT+CIPHEAD=1\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT+CIPSTART=" + serverType + ",\"" + serverAddress + "\"," + serverPort + "\r\n");
        connectTimes++;
        Thread.sleep(3000L);
        String readRes = new String(serialPort.getData());
        serialPort.jeremyNotify();
        try {
            if (readRes.contains("CONNECT OK")) {
                connectSuccessTimes++;
                logger.trace("命令【AT+CIPSTART=" + serverType + ",\"" + serverAddress + "\"," + serverPort + "】连接成功，开始测试，第" + connectSuccessTimes + "次连接成功");
                logConnectInfo();
            } else {
                timeoutTimes++;
                logConnectInfo();
                logger.error("命令【AT+CIPSTART=" + serverType + ",\"" + serverAddress + "\"," + serverPort + "】连接失败，第" + timeoutTimes + "次连接失败");
                serialPort.sendComm("AT+CGATT?\r\n");
                Thread.sleep(100L);
                readRes = new String(serialPort.getData());
                serialPort.jeremyNotify();
                if (!readRes.contains("1")) {
                    logger.error("PDP未激活..等待自动激活(等待时间60S)");
                    Thread.sleep(60000L);
                    init();
                }
            }
        } catch (Exception e) {
            System.out.println("-------【FATAL】你的模块很有可能没开机，或者正在执行的这个命令在指定的延迟时间内没有任何返回-------");
            e.printStackTrace();
            System.exit(0);
        }
    }

    private static void logConnectInfo() throws CustomComException, InterruptedException {
        logger.debug("没收到服务器回复次数：" + canNotGetServerReplayTimes + "次");
        logger.debug("发起连接：" + connectTimes + "次");
        logger.debug("连接成功：" + connectSuccessTimes + "次");
        logger.debug("连接失败：" + timeoutTimes + "次");
        logger.debug("连接中断：" + connectionClosedTimes + "次");
        serialPort.sendComm("AT+CESQ\r\n");
        Thread.sleep(100L);
        serialPort.getData();
        serialPort.jeremyNotify();
        serialPort.sendComm("AT*BANDIND?\r\n");
        Thread.sleep(100L);
        serialPort.getData();
        serialPort.jeremyNotify();
        logger.trace("++++++++++++++++++++++++++++++++++++++++++++++++分割线++++++++++++++++++++++++++++++++++++++++++++++++");
    }

    public static void main(String[] args) throws CustomComException, InterruptedException, IOException {

        File file = new File("cfg\\ServerConfig.txt");
        BufferedReader reader = new BufferedReader(new FileReader(file));
        serverType = reader.readLine();
        serverAddress = reader.readLine();
        serverPort = reader.readLine();
        reader.close();

        logger.debug("当前测试使用" + serverType + "服务器：" + serverAddress + ":" + serverPort);

        // 实例化串口操作类对象
        serialPort = new SerialPortUtils();
        // 创建串口必要参数接收类并赋值，赋值串口号，波特率，校验位，数据位，停止位
        ComParamConfig comParamConfig = new ComParamConfig(jeremyComPort, 115200, 0, 8, 1);
        // 初始化设置,打开串口，开始监听读取串口数据
        serialPort.init(comParamConfig);
        //发送初始化AT ATE0 AT+CIPSHUT AT+CIPSTART
        serialPort.sendComm("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
        Thread.sleep(100L);
        serialPort.sendComm("ATE0\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT^TRACECTRL=0,1,3\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT*EXASSERT=1;&W\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT+CSDT=1;&W\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT+UPGRADE=\"AUTO\",0\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT+CIPHEAD=1\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT+CIPMUX=0\r\n");
        Thread.sleep(100L);
        serialPort.sendComm("AT+CIPSHOWTP=0\r\n");
        Thread.sleep(100L);
        init();
        String readRes;
        String readRes2;
        String hexRes = "";
        //拼接发送数据
        StringBuilder sendDataTmp = new StringBuilder();
        sendDataTmp.append("0");
        for (int i = 0; i <= 255; i++) {
            String hex = intToHex(i);
            if (i < 16) {
                hex = "0" + hex;
            }
            sendDataTmp.append(hex);
        }
        sendDataTmp.append(sendDataTmp);
        int i = 0;

        out:
        while (true) {

            try {
                String sendHexData = sendDataTmp.toString();
                //发送AT+CIPSEND
                int hexDataLength = (sendHexData.length() / 2);
                serialPort.sendComm("AT+CIPSEND=" + hexDataLength + "\r\n");
                Thread.sleep(100L);
                readRes = new String(serialPort.getData());
                serialPort.jeremyNotify();
                if (readRes.contains("CLOSED") | readRes.contains("+CME ERROR:") | readRes.contains("DEACT")) {
                    logger.warn("【" + serverType + "连接中断第" + ++connectionClosedTimes + "次】");
                    logConnectInfo();
                    init();
                    continue;
                }

                //发送数据
                serialPort.sendCommHEX(sendHexData);
                Thread.sleep(350L);
                byte[] readTmp = serialPort.getData();
                readRes = new String(readTmp);
                StringBuilder hexString = new StringBuilder(CommonMethods.bytesToHexString(readTmp));
                logger.trace("串口返回内容hex格式->" + hexString);
                serialPort.jeremyNotify();
                if (readRes.contains("CLOSED") | readRes.contains("+CME ERROR:") | readRes.contains("DEACT")) {
                    logger.warn("【" + serverType + "连接中断第" + ++connectionClosedTimes + "次】");
                    logConnectInfo();
                    init();
                    continue;
                }
                int getDataTime = 1;
                while (!readRes.contains("+IPD")) {
                    logger.debug("串口返回分段" + getDataTime);
                    if (getDataTime == 50) {
                        logger.info("10S过去了都没收到服务器回复的数据");
                        logger.trace("【第" + (i + 1) + "次发送数据完成，匹配失败" + errorCount + "次】");
                        i++;
                        canNotGetServerReplayTimes++;
                        logConnectInfo();
                        continue out;
                    }
                    getDataTime++;
                    Thread.sleep(200L);
                    byte[] readTmp2 = serialPort.getData();
                    readRes2 = new String(readTmp2);
                    String fenduantmp = CommonMethods.bytesToHexString(readTmp2);
                    logger.trace("串口返回内容hex格式->" + fenduantmp);
                    hexString.append(fenduantmp);
                    serialPort.jeremyNotify();
                    readRes = readRes.concat(readRes2);
                    if (readRes.contains("CLOSED") | readRes.contains("+CME ERROR:") | readRes.contains("DEACT")) {
                        logger.warn("【" + serverType + "连接中断第" + ++connectionClosedTimes + "次】");
                        logConnectInfo();
                        init();
                        continue out;
                    }
                }
                if (!readRes.contains(String.valueOf(hexDataLength))) {
                    logger.error("接收数据长度有误");
                }

                Pattern p = Pattern.compile("2B4950442C3531323A\\w+0D0A|2B4950442C3531323A\\w+");
                Matcher m = p.matcher(hexString.toString());
                while (m.find()) {
                    String sub = hexString.substring(m.start(), m.end());
                    hexRes = sub.replace("0D0A", "").substring(18);
                    int hexDataLen = hexRes.length() / 2;
                    logger.trace("【接收数据长度：】" + hexDataLen);
                    if (hexDataLen != hexDataLength) {
                        logger.error("接收数据长度有误");
                    } else {
                        logger.trace("接收数据长度正确");
                    }
                    logger.trace("【接收数据：】" + hexRes);
                }

                if (hexRes.equals(sendHexData)) {
                    logger.trace("【发送数据返回结果匹配成功】");
                } else {
                    logger.error("【发送数据返回结果匹配失败】");
                    errorCount++;
                    flag = true;
                    errList.add(i + 1);
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                logger.error("【发送数据】返回结果匹配失败");
                errorCount++;
                flag = true;
                errList.add(i + 1);
            } catch (Exception e) {
                System.out.println("-------【FATAL】你的模块很有可能没开机，或者正在执行的这个命令在指定的延迟时间内没有任何返回-------");
                e.printStackTrace();
                System.exit(0);
            }
            logger.trace("【第" + (i + 1) + "次发送数据完成，匹配失败" + errorCount + "次】");
            i++;
            logConnectInfo();
            if (flag) {
                logger.error("匹配失败【" + errorCount + "】次，匹配失败的位置：" + errList);
                flag = false;
            }
        }
    }
}

